//: Playground - noun: a place where people can play

import UIKit

//: ### 测试：
// 测试通常是一些代码片段和预期结果的组成
// 单元测试：每部分都依赖特定的输入来测试函数是否正确
// QuickCheck：允许你描述函数的抽象特性并生成测试来验证这些特性

//: ### 构建 QuickCheck
// 1. 生成不同类型的随机数方法
// 2. 实现 Check 函数，然后讲随机数传递给他的特性参数。
// 3. 如果测试失败，可以尽可能缩小测试输入值，测试是否继续失败
// 4. 额外的确保我们检验函数适用于泛型

//: #### 1. 生成随机数

protocol Smaller {
    func smaller() -> Self?
}

protocol Arbitrary: Smaller {
    static func arbitrary() -> Self
}

// 协议 Int 例子

// 生成随机正整数
extension Int: Arbitrary {
    static func arbitrary() -> Int {
        return Int(arc4random())
    }
}

Int.arbitrary()

// 生成随机字符串，先生成随机字符
// arc4random_uniform(区间大小) +区间最小值＝区间内随机数

extension Character: Arbitrary {
    static func arbitrary() -> Character {
        return Character(UnicodeScalar(Int.random(from: 65, length: 22)))
    }
}

func tabulate<A>(times: Int, transform: Int -> A) -> [A] {
    return (0..<times).map(transform)
}

extension Int {
    static func random(from from: Int, to: Int) -> Int {
        return from + (Int(arc4random())%(to - from))
    }
    
    static func random(from from: Int, length: Int) -> Int {
        return Int(arc4random_uniform(UInt32(length)) + UInt32(from))
    }
}

extension String: Arbitrary {
    static func arbitrary() -> String {
        let randomLength = Int.random(from: 0, to: 40)
        let randomCharacters = tabulate(randomLength){_ in
            Character.arbitrary()
        }
        return String(randomCharacters)
    }
}

String.arbitrary()


//: #### 实现 Check 函数

let numberOfIterations = 20

func check1<A: Arbitrary>(message: String, _ property: A -> Bool) -> () {
    for _ in 0..<numberOfIterations {
        let value = A.arbitrary()
        guard property(value) else {
            print("\"\(message)\"doesn't hold \(value)")
            return
        }
    }
    print("\"\(message)\" passed \(numberOfIterations) tests.")
}

// 检测函数特性

extension CGSize {
    var area: CGFloat {
        return width * height
    }
}

// 原来代码有误 == 先

//: ### 缩小范围




extension Int: Smaller {
    func smaller() -> Int? {
        return self == 0 ? nil : self / 2
    }
}

100.smaller()

// 对于缩短字符串的操作来说 去掉第一个字符
extension String: Smaller {
    func smaller() -> String? {
        return isEmpty ? nil : String(characters.dropFirst())
    }
}

"asdasd".smaller()

//: #### 反复缩小范围

func iterateWhile<A>(condition: A -> Bool, initial: A, next: A -> A?) -> A {
    if let x = next(initial) where condition(x) {
        return iterateWhile(condition, initial: x, next: next)
    }
    return initial
}

func check2<A: Arbitrary>(message: String, _ property: A -> Bool) -> () {
    for _ in 0..<numberOfIterations {
        let value = A.arbitrary()
        guard property(value) else {
            let smallerValue = iterateWhile({!property($0)}, initial: value, next: $0.smaller())
        }
    }
}









